package com.emc.esu.api.rest
{
	import com.emc.esu.api.Acl;
	import com.emc.esu.api.Checksum;
	import com.emc.esu.api.EsuApi;
	import com.emc.esu.api.Extent;
	import com.emc.esu.api.Identifier;
	import com.emc.esu.api.ListOptions;
	import com.emc.esu.api.MetadataList;
	import com.emc.esu.api.MetadataTags;
	import com.emc.esu.api.ObjectId;
	import com.emc.esu.api.ObjectPath;
	
	import flash.utils.ByteArray;

	/**
	 * This is an implementation of the ResRestApi that supports automatic retries upon error.
	 */
	public class EsuRetryRestApi implements EsuApi {
		[Bindable]
		/**
		 * Maximum number of retries.  Set to zero to turn off retries.
		 */
		public var retryCount:int = 4;
		
		[Bindable]
		/**
		 * Retry delay in milliseconds
		 */
		public var retryDelay:int = 0;
		
		private var _esu:EsuApi;
		
		/**
		 * Wraps the given EsuApi in a retry wrapper
		 */
		public function EsuRetryRestApi( esu:EsuApi ) {
			this._esu = esu;
		}
		
		
		public function createObject(acl:Acl, metadata:MetadataList, data:ByteArray, mimeType:String, callback:Function, state:Object, checksum:Checksum = null):void {
			var args:Array = new Array( acl, metadata, data, mimeType, checksum );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.createObject, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function createObjectOnPath(path:ObjectPath, acl:Acl, metadata:MetadataList, data:ByteArray, mimeType:String, callback:Function, state:Object, checksum:Checksum = null):void {
			var args:Array = new Array( path, acl, metadata, data, mimeType, checksum );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.createObjectOnPath, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function updateObject(id:Identifier, acl:Acl, metadata:MetadataList, extent:Extent, data:ByteArray, mimeType:String, callback:Function, state:Object, checksum:Checksum = null):void
		{
			var args:Array = new Array( id, acl, metadata, extent, data, mimeType, checksum );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.updateObject, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function setUserMetadata(id:Identifier, metadata:MetadataList, callback:Function, state:Object):void
		{
			var args:Array = new Array( id, metadata );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.setUserMetadata, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function setAcl(id:Identifier, acl:Acl, callback:Function, state:Object):void
		{
			var args:Array = new Array( id, acl );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.setAcl, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function deleteObject(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.deleteObject, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function getUserMetadata(id:Identifier, tags:MetadataTags, callback:Function, state:Object):void
		{
			var args:Array = new Array( id, tags );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getUserMetadata, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function getSystemMetadata(id:Identifier, tags:MetadataTags, callback:Function, state:Object):void
		{
			var args:Array = new Array( id, tags );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getSystemMetadata, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function readObject(id:Identifier, extent:Extent, buffer:ByteArray, callback:Function, state:Object, checksum:Checksum = null):void
		{
			var args:Array = new Array( id, extent, buffer, checksum );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.readObject, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function getAcl(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getAcl, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function deleteUserMetadata(id:Identifier, tags:MetadataTags, callback:Function, state:Object):void
		{
			var args:Array = new Array( id, tags );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.deleteUserMetadata, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function listVersions(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.listVersions, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function versionObject(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.versionObject, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		/**
	     * Deletes a version
	     * @param id the version object to delete
	     * @param callback a callback function with the signature 
	     * <code>function x( state:EsuCallbackState );</code>
	     * @param state an optional user-defined state object to be passed to
	     * the callback method through the EsuCallbackState object.
	     */
	    public function deleteVersion( id:ObjectId, callback:Function, state:Object ):void {
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.deleteVersion, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
	    	
	    }
	    
	    /**
	     * Restores a version of an object to the base revision (i.e. "promotes" a
	     * version to the current version)
	     * @param id the base object
	     * @param vId the version ID to promote
	     * @param callback a callback function with the signature 
	     * <code>function x( state:EsuCallbackState );</code>
	     * @param state an optional user-defined state object to be passed to
	     * the callback method through the EsuCallbackState object.
	     */
	    public function restoreVersion( id:Identifier, vId:ObjectId, callback:Function, state:Object ):void {
			var args:Array = new Array( id, vId );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.restoreVersion, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
	    	
	    }

		
		public function listObjects(tag:Object, options:ListOptions, callback:Function, state:Object):void
		{
			var args:Array = new Array( tag );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.listObjects, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function listObjectsWithMetadata(tag:Object, callback:Function, state:Object):void
		{
			var args:Array = new Array( tag );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.listObjectsWithMetadata, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function getListableTags(tag:Object, callback:Function, state:Object):void
		{
			var args:Array = new Array( tag );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getListableTags, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function listUserMetadataTags(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.listUserMetadataTags, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function queryObjects(xquery:String, callback:Function, state:Object):void
		{
			var args:Array = new Array( xquery );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.queryObjects, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function getAllMetadata(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getAllMetadata, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function listDirectory(path:ObjectPath, options:ListOptions, callback:Function, state:Object):void
		{
			var args:Array = new Array( path, options );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.listDirectory, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
		}
		
		public function getObjectInfo(id:Identifier, callback:Function, state:Object):void
		{
			var args:Array = new Array( id );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getObjectInfo, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();

		}
		
		public function getShareableUrl(id:Identifier, expiration:Date):String
		{
			// Synchronous call, doesn't go to server
			// Just pass down.
			return _esu.getShareableUrl( id, expiration );
		}
		
	    /**
	     * Renames a file or directory within the namespace.
	     * @param source The file or directory to rename
	     * @param destination The new path for the file or directory
	     * @param force If true, the desination file or 
	     * directory will be overwritten.  Directories must be empty to be 
	     * overwritten.  Also note that overwrite operations on files are
	     * not synchronous; a delay may be required before the object is
	     * available at its destination.
	     * @param callback a callback function with the signature 
	     * <code>function x( state:EsuCallbackState );</code>
	     * @param state an optional user-defined state object to be passed to
	     * the callback method through the EsuCallbackState object.
	     */
	    public function rename(source:ObjectPath, destination:ObjectPath, force:Boolean, callback:Function, state:Object):void {
			var args:Array = new Array( source, destination, force );
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.rename, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
	    }
	    /**
	     * Gets the current Atmos server information.  Currently, this simply
	     * returns the version of Atmos that is running.
	     * @param callback a callback function with the signature 
	     * <code>function x( state:EsuCallbackState );</code>
	     * @param state an optional user-defined state object to be passed to
	     * the callback method through the EsuCallbackState object.
	     */
	    public function getServiceInformation(callback:Function, state:Object):void {
			var args:Array = new Array();
			var wrapper:RestRetryWrapper = new RestRetryWrapper( _esu, _esu.getServiceInformation, 
				args, callback, state, retryCount, retryDelay );
				
			wrapper.execute();
	    }
		
	}
}